package org.zhangkun.jmsg.ui.swing.view;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;

import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.browser.TitleEvent;
import org.eclipse.swt.browser.TitleListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.zhangkun.jmsg.bean.User;
import org.zhangkun.jmsg.core.UserManager;
import org.zhangkun.jmsg.ui.swing.listener.MsgViewListener;
import org.zhangkun.jmsg.util.FileUtil;
import org.zhangkun.jmsg.util.GlobalVar;
import org.zhangkun.jmsg.webserver.servlet.ReadFile;

public class SWTMsgView extends MsgPanel {
    public static Display display;
    private static Thread displayThread;
    private static int id;
    private static int shellInstance;
    /**
     *
     */
    private static final long serialVersionUID = -1838293546798077919L;
    public static boolean showNoHTMLMsg = false;
    private Browser browser;
    private Canvas canvas;
    private static String lastSelectPath = ".";

    private boolean loading = true;

    private boolean sendImging;
    private Runnable readAndDispatch;
    public Shell shell;

    public SWTMsgView(MsgViewListener msgViewListener) {
        super(msgViewListener);
        canvas = new Canvas();
        setLayout(new BorderLayout());
        add(canvas, BorderLayout.CENTER);
        setFocusable(true);
        shellInstance++;
        System.setProperty("sun.awt.xembedserver", "true");
        if (display == null) {
            display = Display.getDefault();
            System.out.println("创建SWT Display " + display);
            readAndDispatch = new Runnable() {
                @Override
                public void run() {
                    display.readAndDispatch();
                    if (shellInstance == 0) {
                        System.out.println("销毁SWT Display ..");
                        display.dispose();
                        display = null;
                    }
                }
            };
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (display != null) {
                        try {
                            SwingUtilities.invokeAndWait(readAndDispatch);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }

    private boolean read = false;

    public synchronized void addNotify() {
        // TODO Auto-generated method stub
        super.addNotify();
        display.syncExec(new Runnable() {
            public void run() {
                // 你改界面的代码
                shell = SWT_AWT.new_Shell(display, canvas);
                shell.setAlpha(100);
                shell.setLayout(new FillLayout(SWT.DOWN));
                try {
                    if (System.getProperty("os.name").toLowerCase().contains("windows"))
                        browser = new Browser(shell, SWT.MOZILLA);
                    else
                        browser = new Browser(shell, SWT.WEBKIT);
                } catch (Throwable e) {
                    e.printStackTrace();
                    System.err.println("Use none style.");
                    browser = new Browser(shell, SWT.NONE);
                }
                browser.setUrl("http://127.0.0.1:" + GlobalVar.HTTP_PORT + "/?t=" + id++);
                browser.setDragDetect(false);
                browser.setJavascriptEnabled(true);
                browser.addProgressListener(new ProgressListener() {
                    @Override
                    public void changed(ProgressEvent pe) {
                        // TODO Auto-generated method stub
                        // if (pe.current == pe.total && loading) {
                        // loading = false;
                        // }
                        read = true;
                    }

                    @Override
                    public void completed(ProgressEvent pe) {
                        // TODO Auto-generated method stub
                        loading = false;
                    }
                });
                browser.addTitleListener(new TitleListener() {
                    @Override
                    public void changed(TitleEvent event) {
                        // TODO Auto-generated method stub
                        if (!event.title.equals("")) {
                            executeScript("clearTitle()");
                            new Thread() {
                                private String cmd;

                                public Thread setCmd(String cmd) {
                                    this.cmd = cmd;
                                    return this;
                                }

                                public void run() {
                                    onCmd(cmd);
                                }
                            }.setCmd(event.title).start();
                        }
                    }
                });
                browser.addKeyListener(new KeyListener() {

                    @Override
                    public void keyReleased(KeyEvent arg0) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public void keyPressed(KeyEvent event) {
                        // TODO Auto-generated method stub
                        System.out.println(event);
                    }
                });
                browser.setFocus();
            }
        });
        if (loading)
            waitForLoad();
        msgViewListener.onLoadFinish();
    }

    private void appendImage(String[] selFiles) {
        final StringBuffer sb = new StringBuffer();
        for (int i = 0; i < selFiles.length; i++) {
            String fid = ReadFile.getFileID(selFiles[i]);
            sb.append("<div class=\"imgDiv\"><img ondblclick =\"javascript:openImg('"
                    + fid
                    + "','"
                    + UserManager.me.getIp()
                    + "');\" src=\"http://"
                    + UserManager.me.getIp()
                    + ":"
                    + GlobalVar.HTTP_PORT
                    + "/ReadFile.jsp?fid="
                    + fid
                    + "\" alt=\"加载中..\"/><a href=\"javascript:saveImg('"
                    + fid
                    + "','" + UserManager.me.getIp() + "');\">另存为</a></div>");
        }
        display.syncExec(new Runnable() {
            public void run() {
                executeScript("insertHTML(\"" + esc(sb.toString()) + "\")");
                sendImging = false;
            }
        });
    }

    @Override
    public void appendReceiveMsg(final User user, final String msg) {
        // TODO Auto-generated method stub
        display.syncExec(new Runnable() {
            public void run() {
                executeScript("appendReceiveMsg(\"" + user.getName() + "\",\""
                        + user.getIp() + "\",\"" + user.getGroup() + "\",\""
                        + esc(msg) + "\")");
            }
        });

    }

    @Override
    public void appendSendMsg(final String msg) {
        // TODO Auto-generated method stub
        display.syncExec(new Runnable() {
            public void run() {
                executeScript("updateMeInfo(\"" + UserManager.me.getName()
                        + "\",\"" + UserManager.me.getIp() + "\",\""
                        + UserManager.me.getGroup() + "\")");
                executeScript("appendSendMsg(\"" + esc(msg) + "\")");
            }
        });
    }

    @Override
    public void appendSystemMsg(final String msg) {
        // TODO Auto-generated method stub
        display.syncExec(new Runnable() {
            public void run() {
                executeScript("appendSystemMsg(\"" + esc(msg) + "\")");
            }
        });
    }

    private synchronized void close() {
        display.syncExec(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                Browser.clearSessions();
                try {
                    browser.dispose();
                } catch (Exception e) {
                    // TODO: handle exception
                }
                try {
                    shell.dispose();
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        });
        shellInstance--;
    }

    public String esc(String str) {
        str = str.replaceAll("\\\\", "\\\\\\\\");
        str = str.replaceAll("\"", "\\\\\"");
        str = str.replaceAll("\\r\\n", "\\\\n");
        str = str.replaceAll("\\n", "\\\\n");
        return str;
    }

    public boolean executeScript(String cmd) {
        int resize = 0;
        while (!browser.execute(cmd)) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            resize++;
            if (resize > 5)
                return false;
        }
        return true;
    }

    @Override
    public String getInputMsg() {
        // TODO Auto-generated method stub
        class MyRunnable implements Runnable {
            public String str = null;

            @Override
            public void run() {
                // TODO Auto-generated method stub
                str = (String) browser.evaluate("return getInputText();");
                if (str == null)
                    str = "";
            }
        }
        MyRunnable runnable = new MyRunnable();
        display.syncExec(runnable);
        return runnable.str;
    }

    public void insertImg() {
        System.out.println("insertImg1");
        JFileChooser jfc = new JFileChooser(lastSelectPath);
        jfc.setDialogTitle("选择图片");
        jfc.setMultiSelectionEnabled(true);
        jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        ImagePreview preview = new ImagePreview(jfc);
        jfc.addPropertyChangeListener(preview);
        jfc.setAccessory(preview);
        jfc.setFileFilter(new FileFilter() {

            private String[] fileType = new String[]{"png", "jpg", "jpeg",
                    "bmp", "ico"};

            @Override
            public String getDescription() {
                // TODO Auto-generated method stub
                return "图片文件(*.png,*.jpg,*.jpeg,*.bmp,*.ico)";
            }

            @Override
            public boolean accept(File f) {
                // TODO Auto-generated method stub
                if (f.isDirectory())
                    return true;
                if (f.canRead()) {
                    for (int i = 0; i < fileType.length; i++)
                        if (f.getAbsolutePath().toLowerCase()
                                .endsWith(fileType[i]))
                            return true;
                }
                return false;
            }
        });
        jfc.setAcceptAllFileFilterUsed(false);
        if (jfc.showDialog(this, "插入") == JFileChooser.APPROVE_OPTION) {
            lastSelectPath = jfc.getCurrentDirectory().getAbsolutePath();
            File[] fs = jfc.getSelectedFiles();
            System.out.println("insertImg2");
            if (fs.length != 0) {
                String[] selFiles = new String[fs.length];
                for (int i = 0; i < fs.length; i++)
                    selFiles[i] = fs[i].getAbsolutePath();
                System.out.println("insertImg3");
                appendImage(selFiles);
                System.out.println("insertImg4");
            }
        }
        sendImging = false;
    }

    public void onCmd(String cmd) {
        System.out.println("cmd " + cmd);
        if (!cmd.equals("")) {
            if (cmd.equals("sendJMsgEvent")) {
                class MyRunnable implements Runnable {
                    private String msg;

                    public String getMsg() {
                        return msg;
                    }

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        msg = (String) browser
                                .evaluate("return getSendMeMsg()");
                    }
                }
                MyRunnable myRunnable = new MyRunnable();
                display.syncExec(myRunnable);
                msgViewListener.onSendJMsgApplicationEvent(myRunnable.getMsg());
            }
            if (cmd.equals("screenCaptureEvent")) {
                String file = ScreenCapturing.capturing();
                if (file != null)
                    appendImage(new String[]{file});
            } else if (cmd.equals("startInputEvent")) {
                msgViewListener.onStartInput();
            } else if (cmd.equals("endInputEvent")) {
                msgViewListener.onEndInput();
            } else if (cmd.equals("sendMsgEvent")) {
                msgViewListener.onSendMsgEvent();
            } else if (cmd.equals("shakeWindowEvent")) {
                msgViewListener.onSendWindowShake();
            } else if (cmd.equals("sendImgEvent")) {
                if (!sendImging) {
                    sendImging = true;
                    insertImg();
                }
            } else if (cmd.startsWith("saveImgEvent")) {
                saveImg(cmd.substring(13).split("#"));
            } else if (cmd.startsWith("openImgEvent")) {
                openImg(cmd.substring(13).split("#"));
            }
        }
    }

    public synchronized void open() {
        display.syncExec(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                executeScript("createEditor();");
            }
        });
    }

    @Override
    public void removeNotify() {
        // TODO Auto-generated method stub
        close();
        super.removeNotify();
    }

    public void saveImg(String[] strings) {
        JFileChooser jfc = new JFileChooser(lastSelectPath);
        jfc.setDialogTitle("保存图片");
        jfc.setMultiSelectionEnabled(true);
        jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        if (jfc.showDialog(this, "保存") == JFileChooser.APPROVE_OPTION) {
            lastSelectPath = jfc.getCurrentDirectory().getAbsolutePath();
            File fs = jfc.getSelectedFile();
            String downFilePath = ReadFile.getFilePath(strings[0]);
            if (downFilePath == null) {
                FileUtil.downFile(strings[1], strings[0], fs);
            } else {
                FileUtil.copyFile(new File(downFilePath), fs);
            }
        }
    }

    public void openImg(String[] strings) {
        String path = ReadFile.getFilePath(strings[0]);
        File fs;
        try {
            fs = FileUtil.createTempFile(strings[0], ".png");
            if (path == null) {
                FileUtil.downFile(strings[1], strings[0], fs);
                if (Desktop.isDesktopSupported()) {
                    Desktop desktop = Desktop.getDesktop();
                    desktop.open(fs);
                }
            } else {
                if (Desktop.isDesktopSupported()) {
                    Desktop desktop = Desktop.getDesktop();
                    desktop.open(new File(path));
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void setInputMsg(final String msg) {
        // TODO Auto-generated method stub
        display.syncExec(new Runnable() {
            public void run() {
                executeScript("setInputText(\"" + esc(msg) + "\")");
            }
        });
    }

    @Override
    public synchronized void setUseHTML(final boolean use) {
        // TODO Auto-generated method stub
        System.out.println("setUseHTML " + use);
        display.syncExec(new Runnable() {
            public void run() {
                if (use)
                    System.out.println("Browser execute updateUseHtml(true) "
                            + executeScript("updateUseHtml(true)"));
                else {
                    System.out.println("Browser execute updateUseHtml(false) "
                            + executeScript("updateUseHtml(false)"));
                    if (!showNoHTMLMsg) {
                        System.out.println("showNoHTMLMsg");
                        executeScript("showNoHTMLMsg()");
                        showNoHTMLMsg = true;
                    }
                }
            }
        });
    }

    private synchronized void waitForLoad() {
        int loadTime = 0;
        while (loading) {
            loadTime++;
            if (read) {
                loadTime = 0;
                read = false;
            }
            if (loadTime > 50)
                break;
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        loading = false;
    }

}
